package middleware

import (
	"com.codingq92/go-chat/app/resp"
	"com.codingq92/go-chat/global"
	"com.codingq92/go-chat/services"
	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"strconv"
	"time"
)

// JWTAuth jwt鉴权(给所有需要登录接口鉴权)
func JWTAuth(guardName string) gin.HandlerFunc {
	return func(c *gin.Context) {
		tokenStr := c.Request.Header.Get("Authorization")
		if tokenStr == "" {
			resp.TokenFail(c)
			c.Abort()
			return
		}
		tokenStr = tokenStr[len(services.TokenType)+1:]
		// Token 解析校验
		token, err := jwt.ParseWithClaims(tokenStr, &services.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
			return []byte(global.Config.Jwt.Secret), nil
		})
		// 出错 & 黑名单校验
		if err != nil || services.JwtService.IsInBlacklist(tokenStr) {
			resp.TokenFail(c)
			c.Abort()
			return
		}
		claims := token.Claims.(*services.CustomClaims)
		// Token 发布者校验
		if claims.Issuer != guardName {
			resp.TokenFail(c)
			c.Abort()
			return
		}
		// token续签: 剩余有效期小于配置的剩余时间最小阈值直接刷新token 单位 秒
		if claims.ExpiresAt-time.Now().Unix() < global.Config.Jwt.Refresh {
			lock := global.NewDistributedLock("refresh_token_lock", global.Config.Jwt.JwtBlackListTtl)
			if lock.Get() {
				err, user := services.JwtService.GetUserInfo(guardName, claims.Id)
				if nil != err {
					lock.Release()
				} else {
					tokenData, _, _ := services.JwtService.CreateToken(guardName, user)
					c.Header("new-token", tokenData.AccessToken)
					c.Header("new-expires-in", strconv.Itoa(tokenData.ExpiresIn))
					_ = services.JwtService.JoinBlackList(token)
				}
			}
		}
		c.Set("id", claims.Id)
		c.Set("token", token)
	}
}
